﻿using System.Diagnostics.Eventing.Reader;

namespace System;

/// <summary>
/// 基于数组实现的自定义队列(支持自动扩容、头插)(线程安全)
/// </summary>
/// <typeparam name="T"></typeparam>
public sealed class ArrayQueue<T>
{
    private readonly object _synchronizedLock = new object();

    private int _count = 0;

    private int _capacity = 0;

    private int _getIndex = 0;

    private int _setIndex = 0;

    private T[] _array;

    public int Count => _count;

    public bool IsEmpty => Count == 0;

    public ArrayQueue() : this(8) { }

    public ArrayQueue(int capacity)
    {
        _capacity = capacity;
        if (_capacity < 1)
            _capacity = 8;
        _array = new T[_capacity];
    }

    /// <summary>
    /// 入队
    /// </summary>
    /// <param name="entity"></param>
    public void Enqueue(T entity)
    {
        lock (_synchronizedLock)
        {
            if (_setIndex < _capacity) // 存
            {
                _array[_setIndex] = entity;
                _setIndex++;
                _count++;
            }
            if (_count >= _capacity) // 扩容
                Dilatation();

            if (_setIndex >= _capacity) //setIndex 回头
            {
                _setIndex = 0;
                _array[_setIndex] = default(T);
            }
        }
    }


    /// <summary>
    /// (插队)插入队列头部
    /// </summary>
    /// <param name="entity"></param>
    public void EnqueueHead(T entity)
    {
        lock (_synchronizedLock)
        {
            if (_count == 0)
            {
                Enqueue(entity);
            }
            else
            {
                int headSetIndex = _getIndex - 1;
                if (headSetIndex < 0) headSetIndex = _capacity - 1;

                _array[headSetIndex] = entity;
                _count++;
                _getIndex = headSetIndex;

                if (_count >= _capacity) Dilatation();
            }
        }
    }

    /// <summary>
    /// 出队
    /// </summary>
    /// <param name="entity"></param>
    /// <returns></returns>
    public bool TryDequeue([MaybeNullWhen(false)] out T result)
    {
        result = default(T);
        lock (_synchronizedLock)
        {
            if (Count == 0)
                return false;

            result = _array[_getIndex];
            _array[_getIndex] = default(T);
            _getIndex++;
            _count--;
            if (_getIndex >= _capacity) _getIndex = 0;
        }
        return true;
    }

    /// <summary>
    /// 读取第一个对象而不取出队列
    /// </summary>
    /// <param name="result"></param>
    /// <returns></returns>
    public bool TryPeek([MaybeNullWhen(false)] out T result)
    {
        result = default(T);
        lock (_synchronizedLock)
        {
            if (Count == 0)
                return false;

            result = _array[_getIndex];
        }
        return true;
    }

    /// <summary>
    /// 自动扩容
    /// </summary>
    private void Dilatation()
    {
        int newCapacity = _capacity * 2;
        T[] newArray = new T[newCapacity];
        int firstLen = _capacity - _getIndex;
        Array.Copy(_array, _getIndex, newArray, 0, firstLen);

        if (_setIndex > 0 && _setIndex < _capacity)
            Array.Copy(_array, 0, newArray, firstLen, _setIndex);

        _setIndex = _capacity;
        _capacity = newCapacity;
        _array = newArray;
        _getIndex = 0;
    }

}